#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <unistd.h>
#include <errno.h>
#include <signal.h>
#include <arpa/inet.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <sys/epoll.h>
#include <sys/time.h>
#include <signal.h>

struct Server{
    int socket_fd;
    socklen_t ser_len;
    socklen_t cli_len;
    struct sockaddr_in ser_addr;
    struct sockaddr_in cli_addr;
} ServerData;
struct epoll_event *events;
int epoll_fd;

void close_socket(int signum) {
    printf("signal : %d\n", signum);
    close(ServerData.socket_fd);
    free(events);
    close(epoll_fd);
    exit(signum); 
}

int main(int argc, char **argv)
{
    int optlen, option;
    struct epoll_event udp_event;
    signal(SIGINT, close_socket);
    ServerData.socket_fd = socket(PF_INET, SOCK_DGRAM, 0);
    if (ServerData.socket_fd < 0) {
        perror("socket");
        return -1;
    }

    optlen=sizeof(option);
    option=1;
    //设置套接字选项，地址和端口可以复用
    if (setsockopt(ServerData.socket_fd, SOL_SOCKET, SO_REUSEADDR|SO_REUSEPORT, (void *)&option, optlen) < 0) {
        perror("setsockopt failed");
        return -1;
    }
    ServerData.ser_len = sizeof(ServerData.ser_addr);
    ServerData.ser_addr.sin_family      = AF_INET;
    ServerData.ser_addr.sin_addr.s_addr = INADDR_ANY;
    ServerData.ser_addr.sin_port        = htons(atoi(argv[1]));
    int ret = bind(ServerData.socket_fd, (struct sockaddr *) &ServerData.ser_addr, ServerData.ser_len);
    if (ret < 0) {
        perror("bind");
        return -1;
    }
    ServerData.cli_len = sizeof(ServerData.cli_addr);

    epoll_fd = epoll_create(1);
    if (epoll_fd < 0) {
        perror("epoll_create");
        close(ServerData.socket_fd);
        return -1;
    }
    udp_event.events = EPOLLIN;
    udp_event.data.fd = ServerData.socket_fd;
    if (epoll_ctl(epoll_fd, EPOLL_CTL_ADD, ServerData.socket_fd, &udp_event) < 0) {
        perror("epoll_ctl");
        close(ServerData.socket_fd);
        close(epoll_fd);
        return -1;
    }

    events = (struct epoll_event *)malloc(sizeof(struct epoll_event)*20);
    while (1) {
        int event_nums = epoll_wait(epoll_fd, events, 20, -1);
        if (event_nums < 0) {
            printf("wait");
        } else {
            char buf[128] = {'\0'};
            for (int i = 0; i < event_nums; i++) {
                if (ServerData.socket_fd == events[i].data.fd) {
                    recvfrom(events[i].data.fd, buf, 128, 0, (struct sockaddr *)&ServerData.cli_addr, &ServerData.cli_len);
                    printf("recvfrom : %s\n", buf);
                }
            }
        }
    }
    return 0;
}